from abc import ABC, abstractmethod
from typing import Dict

# 商品类
class Product:
    def __init__(self, id: int, name: str, price: float):
        self.id = id
        self.name = name
        self.price = price
    
    def __str__(self):
        return f"Product(id={self.id}, name='{self.name}', price={self.price})"

# 抽象主题接口
class IProductDao(ABC):
    @abstractmethod
    def get_product(self, product_id: int) -> Product:
        pass

# 真实主题类
class ProductDaoImpl(IProductDao):
    def get_product(self, product_id: int) -> Product:
        # 模拟从数据库查询
        print(f"从数据库查询商品ID: {product_id}")
        # 这里应该是真实的数据库查询，我们模拟返回数据
        if product_id == 1:
            return Product(1, "iPhone 13", 5999.0)
        elif product_id == 2:
            return Product(2, "MacBook Pro", 12999.0)
        elif product_id == 3:
            return Product(3, "AirPods Pro", 1499.0)
        else:
            raise ValueError(f"找不到ID为{product_id}的商品")

# 缓存代理类
class ProductCacheProxy(IProductDao):
    def __init__(self, real_dao: IProductDao):
        self.real_dao = real_dao
        self.cache: Dict[int, Product] = {}
    
    def get_product(self, product_id: int) -> Product:
        # 先检查缓存
        if product_id in self.cache:
            print(f"从缓存获取商品ID: {product_id}")
            return self.cache[product_id]
        
        # 缓存中没有，调用真实对象查询
        product = self.real_dao.get_product(product_id)
        
        # 将查询结果存入缓存
        self.cache[product_id] = product
        print(f"将商品ID {product_id} 存入缓存")
        
        return product

# 客户端代码
def client_code(product_dao: IProductDao, product_id: int):
    print(f"\n客户端查询商品ID: {product_id}")
    product = product_dao.get_product(product_id)
    print(f"查询结果: {product}")